package thesis.filesharing.web.controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import thesis.filesharing.bo.ClassBO;
import thesis.filesharing.bo.DocumentFileBO;
import thesis.filesharing.bo.ExerciseFileBO;
import thesis.filesharing.bo.SemesterBO;
import thesis.filesharing.bo.StudentBO;
import thesis.filesharing.common.valueobjects.SearchClassValueObject;
import thesis.filesharing.model.Clazz;
import thesis.filesharing.model.DocumentFile;
import thesis.filesharing.model.ExerciseFile;
import thesis.filesharing.model.Student;
import thesis.filesharing.web.auth.AuthUtil;
import thesis.filesharing.web.util.PropertiesUtil;

import com.google.appengine.api.blobstore.BlobInfo;
import com.google.appengine.api.blobstore.BlobInfoFactory;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

@Controller
public class UploadFileController {
	
	private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
	private BlobInfoFactory blobInfoFactory = new BlobInfoFactory();
	
	@Autowired
	private StudentBO studentBO;
	
	@Autowired
	private ExerciseFileBO exerciseFileBO;
	
	@Autowired
	private DocumentFileBO documentFileBO;
	
	@Autowired
	private ClassBO classBO;
	
	@Autowired
	private SemesterBO semesterBO;
	
	@PreAuthorize("hasRole('ROLE_LECTURER')")
	@RequestMapping(value = "/lecturer/uploadDocument", method = RequestMethod.GET)
	public String uploadDocument(ModelMap model) {
		String lecturerId = AuthUtil.getCurrentAuthenticatedUsername();
		if (lecturerId != null) {
			SearchClassValueObject searchObj = new SearchClassValueObject(null, null, lecturerId, semesterBO.getCurrentSemester().getSemesterName());
			List<Clazz> classes = classBO.searchClasses(searchObj);
			model.addAttribute("classes", classes);
		}
		return "lecturer/uploadDocument";
	}
	
	@PreAuthorize("hasRole('ROLE_LECTURER')")
	@RequestMapping(value = "/lecturer/processUploadDocument", method = RequestMethod.POST)
	public ModelAndView processUploadDocument(HttpServletRequest request, HttpSession session) {
		String[] classKeys = request.getParameterValues("checkItem");
		Map<String, List<BlobKey>> blobMaps = blobstoreService.getUploads(request);
		List<BlobKey> blobKeys = blobMaps.get("uploadFile");
		
		List<DocumentFile> documentFiles = new ArrayList<DocumentFile>();
		DocumentFile documentFile = null;
		BlobInfo blobInfo = null;
		
		for (BlobKey blobKey : blobKeys) {
			blobInfo = blobInfoFactory.loadBlobInfo(blobKey);
			documentFile = new DocumentFile(blobInfo.getFilename(), blobInfo.getSize(), 
					blobInfo.getContentType(), blobInfo.getCreation(), blobKey.getKeyString());
			documentFiles.add(documentFile);
		}
		
		documentFileBO.saveDocumentFiles(documentFiles, classKeys);
		session.setAttribute("msg", PropertiesUtil.getProperty("file.upload.success"));
		
		return new ModelAndView(new RedirectView("/lecturer/uploadDocument.html"));
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/getUploadExerciseFileKeyAjax", method = RequestMethod.GET)
	public void getUploadExerciseFileKey(
			@RequestParam(value = "exerciseKey", required = true) String exerciseKey,
			@RequestParam(value = "classKey", required = true) String classKey,
			@RequestParam(value = "s", required = true) boolean submitEver,
			HttpServletResponse response) throws IOException {
		PrintWriter out = response.getWriter();
		String uploadKey = null;
		if (!submitEver) {
			uploadKey = blobstoreService.createUploadUrl("/student/processUploadExerciseFile.html?classKey=" + classKey + "&exerciseKey=" + exerciseKey);
		} else {
			uploadKey = blobstoreService.createUploadUrl("/student/processUpdateExerciseFile.html?classKey=" + classKey + "&exerciseKey=" + exerciseKey);
		}
		out.print(uploadKey);
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/processUploadExerciseFile", method = RequestMethod.POST)
	public ModelAndView processUploadExerciseFile(
			@RequestParam(value = "exerciseKey", required = true) String exerciseKey,
			@RequestParam(value = "classKey", required = true) String classKey,
			HttpServletRequest request) {
		
		Map<String, List<BlobKey>> blobMaps = blobstoreService.getUploads(request);
		if (blobMaps != null) {
			List<BlobKey> blobKeys = blobMaps.get("uploadFile");
			if (blobKeys != null && !blobKeys.isEmpty()) {
				BlobInfo blobInfo = null;
				List<ExerciseFile> exerciseFiles = new ArrayList<ExerciseFile>();
				for (BlobKey blobKey : blobKeys) {
					blobInfo = blobInfoFactory.loadBlobInfo(blobKey);
					if (blobInfo != null) {
						ExerciseFile exerciseFile = new ExerciseFile(blobInfo.getFilename(), blobInfo.getSize(), 
								blobInfo.getContentType(), new Date(), blobInfo.getBlobKey().getKeyString(), true);
						exerciseFiles.add(exerciseFile);
					}
				}
				String studentId = AuthUtil.getCurrentAuthenticatedUsername();
				if (studentId != null) {
					Student student = studentBO.findStudentById(studentId);
					if (student != null) {
						Key studentKey = student.getStudentKey();
						exerciseFileBO.saveExerciseFileCollection(exerciseFiles, studentKey, KeyFactory.stringToKey(classKey), KeyFactory.stringToKey(exerciseKey));
						request.getSession().setAttribute("msg", PropertiesUtil.getProperty("exerciseFile.upload.success"));
					}
				}
			}
		}
		
		return new ModelAndView(new RedirectView("/student/listExercises.html?key=" + classKey));
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/processUpdateExerciseFile", method = RequestMethod.POST)
	public ModelAndView processUpdateExerciseFile(
			@RequestParam(value = "exerciseKey", required = true) String exerciseKey,
			@RequestParam(value = "classKey", required = true) String classKey,
			HttpServletRequest request) {
		Map<String, List<BlobKey>> blobMaps = blobstoreService.getUploads(request);
		if (blobMaps != null) {
			List<BlobKey> blobKeys = blobMaps.get("uploadFile");
			if (blobKeys != null && !blobKeys.isEmpty()) {
				String studentId = AuthUtil.getCurrentAuthenticatedUsername();
				if (studentId != null) {
					Student student = studentBO.findStudentById(studentId);
					if (student != null) {
						Key studentKey = student.getStudentKey();
						
						// Delete old files
						List<ExerciseFile> oldFiles = exerciseFileBO.listExerciseFilesStudentOrGroupUploadedPerExercise(KeyFactory.stringToKey(exerciseKey), studentKey, KeyFactory.stringToKey(classKey));
						List<Key> oldFileKeys = new ArrayList<Key>();
						List<BlobKey> oldFileBlobKeys = new ArrayList<BlobKey>();
						for (ExerciseFile f : oldFiles) {
							oldFileKeys.add(f.getExerciseFileKey());
							oldFileBlobKeys.add(new BlobKey(f.getExerciseFileBlobKey()));
						}
						exerciseFileBO.deleteExerciseFiles(oldFileKeys, KeyFactory.stringToKey(exerciseKey));
						blobstoreService.delete(oldFileBlobKeys.toArray(new BlobKey[oldFileBlobKeys.size()]));
						
						// Create new files
						BlobInfo blobInfo = null;
						List<ExerciseFile> exerciseFiles = new ArrayList<ExerciseFile>();
						for (BlobKey blobKey : blobKeys) {
							blobInfo = blobInfoFactory.loadBlobInfo(blobKey);
							if (blobInfo != null) {
								ExerciseFile exerciseFile = new ExerciseFile(blobInfo.getFilename(), blobInfo.getSize(), 
										blobInfo.getContentType(), new Date(), blobInfo.getBlobKey().getKeyString(), true);
								exerciseFiles.add(exerciseFile);
							}
						}
						exerciseFileBO.saveExerciseFileCollection(exerciseFiles, studentKey, KeyFactory.stringToKey(classKey), KeyFactory.stringToKey(exerciseKey));
						request.getSession().setAttribute("msg", PropertiesUtil.getProperty("exerciseFile.update.success"));
					}
				}
			}
		}
		
		return new ModelAndView(new RedirectView("/student/listExercises.html?key=" + classKey));
	}
}
